package com.newcapec.common.utils;

import com.alibaba.fastjson.JSONObject;
import com.newcapec.modules.sys.service.SysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.io.File;
import java.net.URLEncoder;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 人脸平台api工具
 *
 * @author steven
 */
@Slf4j
@Component("aifaceApiUtils")
public class AifaceApiUtils {

    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private RedisTemplate redisTemplate;
    //人脸平台access_token在redis中存储的key
    private static final String redisAifaceKey = "aiface:access:token";
    //    public static final String IOT_TOKEN_CACHE_KEY = "passcard:cache_iot_token";
    //人脸服务平台接口URL
    private static final String oauthUrl =  "/oauth/token";
    private static final String addPersonUrl =  "/managerapi/addperson";
    private static final String updatePersonUrl =  "/managerapi/updateperson";
    private static final String updatePhotoUrl =  "/managerapi/updatephoto";
    private static final String checkPhotoUrl =  "/onlineapi/checkphoto";
    private static final String removePersonUrl =  "/managerapi/removeperson";

    /**
     * 基本接口 获取令牌
     * 请求token并缓存 令牌有效期有一个自然日
     * 申请后系统缓存下来使用，不要每次都去申请令牌
     * 当令牌过期时再去申请
     */
    public void cacheToken() {
        String aifaceUrl = sysConfigService.getValue(ConfigConstant.AIFACE_URL);
        String aifaceAppKey = sysConfigService.getValue(ConfigConstant.AIFACE_APP_KEY);
        String aifaceAppSecret = sysConfigService.getValue(ConfigConstant.AIFACE_APP_SECRET);
        String aifaceSecretKey = sysConfigService.getValue(ConfigConstant.AIFACE_SECRET_KEY);
        try {
            //请求的header值
            JSONObject reqHeader = new JSONObject();
            reqHeader.put("app_key", aifaceAppKey);

            //请求基本业务数据
            JSONObject json = new JSONObject();
            json.put("app_secret", aifaceAppSecret);
            //将基本业务参数加密
            String requestData = ThreeDESUtils.encryptMode(aifaceSecretKey, json.toString());

            //请求的参数
            JSONObject params = new JSONObject();
            params.put("request_data", requestData);

            String responseText = HttpRequestUtils.httpPostForm(aifaceUrl + oauthUrl, params, reqHeader);
            log.error("申请token返回信息!{}" + responseText);
            AifaceResponse aifaceResponse = new AifaceResponse(aifaceSecretKey, responseText);
            if(aifaceResponse.getCode() == 1){
                Long time = getRemainSecondsOneDay(new Date()) + 5;
                String redisKey = redisAifaceKey;
                //记录到redis
                redisTemplate.opsForValue().set(redisKey, aifaceResponse.getResponseData().getString("access_token"), time, TimeUnit.SECONDS);
            } else {
                log.error("申请token!{}" + aifaceResponse.getMsg());
                throw new RuntimeException("申请token!" + aifaceResponse.getMsg());
            }
        } catch (Exception e) {
            log.error("申请token!{}" + e.getMessage());
            throw new RuntimeException("申请token!原因:{}" + e.getMessage());
        }
    }

    public Object getFaceToken() {
        //如果缓存中的token为空，重新请求缓存token
        String redisKey = redisAifaceKey;
        Object token = redisTemplate.opsForValue().get(redisAifaceKey);
        if (StringUtils.isBlank(token == null ? "" : token.toString())) {
            cacheToken();
        }
        token = redisTemplate.opsForValue().get(redisKey);
        return token;
    }

    /**
     * 添加人员
     * 此时服务接口进行判断，
     * 如果指定的人员已经存在，则更新人员信息，
     * 对于添加人员时是否要进行照片合格性的检验，可以由调用方进行指定。
     */
    public AifaceResponse addPerson(File photo, String outId, String name, Integer validity) {
        String aifaceUrl = sysConfigService.getValue(ConfigConstant.AIFACE_URL);
        String aifaceSecretKey = sysConfigService.getValue(ConfigConstant.AIFACE_SECRET_KEY);
        String eCode = sysConfigService.getValue(ConfigConstant.AIFACE_ECODE);
        try {
            //参数验证
            paramVerify(photo != null, "参数值不能为空[photo]");
            paramVerify(StringUtils.isNotEmpty(outId), "参数值不能为空[outId]");
            paramVerify(StringUtils.isNotEmpty(name), "参数值不能为空[name]");

            //获取token
            Object token = getFaceToken();

            //处理请求header
            JSONObject reqHeader = new JSONObject();
            reqHeader.put("access_token", token.toString());

            //加密基本业务参数
            JSONObject json = new JSONObject();
            json.put("outid", outId);
            json.put("name", name);
            json.put("ecode", eCode);
            json.put("validity", validity);
            String requestData = ThreeDESUtils.encryptMode(aifaceSecretKey, json.toString());

            //处理照片和参数数据
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.addBinaryBody("photo", photo, ContentType.MULTIPART_FORM_DATA, UUID.randomUUID() + ".jpg");
            //获取照片签名
            HMAC_SHA1 sha1 = new HMAC_SHA1(aifaceSecretKey);
            String photoSign = sha1.genHMAC(HMAC_SHA1.getImageStr(photo.getAbsolutePath()));
            photoSign = URLEncoder.encode(photoSign, "UTF-8");
            builder.addTextBody("photosign", photoSign);
            builder.addTextBody("request_data", requestData, ContentType.APPLICATION_JSON);

            String responseText = HttpRequestUtils.httpPostMultipart(aifaceUrl + addPersonUrl, builder, reqHeader);
            //请求返回消息体处理
            if (responseText == null) {
                log.error("『addperson--error』:{}", "消息体返回空");
            } else {
                JSONObject responseJson = JSONObject.parseObject(responseText);
                if (responseJson.containsKey("errcode")) {//请求失败
                    //-1001	INTERFACE_NOTSUPPORT	接口内容暂不支持；主要是在某些部署模式下，部分接口内容不支持
                    //-2001	INVALID_TOKEN	无效的token或者token已过期
                    //-2002	INVALID_APPKEY_SECRET	无效的app_key或者app_secret
                    //-3001	NOT_GRANTED	未授权的操作
                    if ("-2001".equals(responseJson.getString("errcode"))) {
                        redisTemplate.delete(redisAifaceKey);
                        cacheToken();
                    } else {
                        log.error("『addperson--error』:{}", responseJson);
                    }
                }
            }
            AifaceResponse aifaceResponse = new AifaceResponse(aifaceSecretKey, responseText);
            return aifaceResponse;
        } catch (Exception e) {
            log.error("--addperson--error:{}" + e);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 更新人员信息
     * 接入方 向认证平台发送请求，要求更新系统中指定人员的信息。
     */
    public AifaceResponse updatePerson(String outId, String outIdNew, String nameNew, String deptNew) {
        String aifaceUrl = sysConfigService.getValue(ConfigConstant.AIFACE_URL);
        String aifaceSecretKey = sysConfigService.getValue(ConfigConstant.AIFACE_SECRET_KEY);
        String eCode = sysConfigService.getValue(ConfigConstant.AIFACE_ECODE);
        try {
            //参数验证
            paramVerify(StringUtils.isNotEmpty(outId), "参数值不能为空[outId]");
            paramVerify((StringUtils.isNotEmpty(outIdNew) || StringUtils.isNotEmpty(nameNew) || StringUtils.isNotEmpty(deptNew)),
                    "缺少参数[outIdNew]/[nameNew]/[deptNew]");

            //获取token
            Object token = getFaceToken();

            //处理请求header
            JSONObject reqHeader = new JSONObject();
            reqHeader.put("access_token", token.toString());

            //加密基本业务参数
            JSONObject json = new JSONObject();
            json.put("outid", outId);
            json.put("outid_new", outIdNew);
            json.put("name_new", nameNew);
            json.put("dept_new", deptNew);
            json.put("ecode", eCode);
            String requestData = ThreeDESUtils.encryptMode(aifaceSecretKey, json.toString());

            //整理form表单入参,无图片
            JSONObject params = new JSONObject();
            params.put("request_data", requestData);

            String responseText = HttpRequestUtils.httpPostForm(aifaceUrl + updatePersonUrl, params, reqHeader);
            AifaceResponse aifaceResponse = new AifaceResponse(aifaceSecretKey, responseText);
            return aifaceResponse;
        } catch (Exception e) {
            log.error("--updateperson--error:" + e.getMessage());
            throw new RuntimeException("--updateperson--error:" + e.getMessage());
        }
    }

    /**
     * 更新人员照片
     * 接入方 向认证平台发送请求，要求更新系统中指定人员的照片信息。
     */
    public AifaceResponse updatePhoto(File photo, String outId, Integer validity) {
        String aifaceUrl = sysConfigService.getValue(ConfigConstant.AIFACE_URL);
        String aifaceSecretKey = sysConfigService.getValue(ConfigConstant.AIFACE_SECRET_KEY);
        String eCode = sysConfigService.getValue(ConfigConstant.AIFACE_ECODE);
        try {
            //参数验证
            paramVerify(photo != null, "参数值不能为空[photo]");
            paramVerify(StringUtils.isNotEmpty(outId), "参数值不能为空[outId]");

            //获取token
            Object token = getFaceToken();

            //处理请求header
            JSONObject reqHeader = new JSONObject();
            reqHeader.put("access_token", token.toString());

            //加密基本业务参数
            JSONObject json = new JSONObject();
            json.put("outid", outId);
            json.put("ecode", eCode);
            json.put("validity", validity);
            String requestData = ThreeDESUtils.encryptMode(aifaceSecretKey, json.toString());

            //处理图片和参数
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.addBinaryBody("photo", photo, ContentType.MULTIPART_FORM_DATA, UUID.randomUUID() + ".jpg");
            //获取照片签名
            HMAC_SHA1 sha1 = new HMAC_SHA1(aifaceSecretKey);
            String photoSign = sha1.genHMAC(HMAC_SHA1.getImageStr(photo.getAbsolutePath()));
            photoSign = URLEncoder.encode(photoSign, "UTF-8");
            builder.addTextBody("photosign", photoSign);
            builder.addTextBody("request_data", requestData, ContentType.APPLICATION_JSON);

            String responseText = HttpRequestUtils.httpPostMultipart(aifaceUrl + updatePhotoUrl, builder, reqHeader);
            AifaceResponse aifaceResponse = new AifaceResponse(aifaceSecretKey, responseText);
            return aifaceResponse;
        } catch (Exception e) {
            log.error("--updatephoto--error:" + e.getMessage());
            throw new RuntimeException("--updatephoto--error:" + e.getMessage());
        }
    }

    /**
     * 删除人员
     * 接入方 向认证平台发送请求，要求删除人员信息。
     */
    public AifaceResponse removePerson(String outId) {
        String aifaceUrl = sysConfigService.getValue(ConfigConstant.AIFACE_URL);
        String aifaceSecretKey = sysConfigService.getValue(ConfigConstant.AIFACE_SECRET_KEY);
        String eCode = sysConfigService.getValue(ConfigConstant.AIFACE_ECODE);
        try {
            //参数验证
            paramVerify(StringUtils.isNotEmpty(outId), "参数值不能为空[outId]");

            //获取token
            Object token = getFaceToken();

            //处理请求header
            JSONObject reqHeader = new JSONObject();
            reqHeader.put("access_token", token.toString());

            //加密基本业务参数
            JSONObject json = new JSONObject();
            json.put("outid", outId);
            json.put("ecode", eCode);
            String requestData = ThreeDESUtils.encryptMode(aifaceSecretKey, json.toString());

            //整理form表单入参
            JSONObject params = new JSONObject();
            params.put("request_data", requestData);

            String responseText = HttpRequestUtils.httpPostForm(aifaceUrl + removePersonUrl, params, reqHeader);
            AifaceResponse aifaceResponse = new AifaceResponse(aifaceSecretKey, responseText);
            return aifaceResponse;
        } catch (Exception e) {
            log.error("--removePerson--error:" + e.getMessage());
            throw new RuntimeException("--removePerson--error:" + e.getMessage());
        }
    }

    /**
     * 人脸存在性检测
     */
    public AifaceResponse checkPersonByPhoto(File photo, String outId){
        String aifaceUrl = sysConfigService.getValue(ConfigConstant.AIFACE_URL);
        String aifaceSecretKey = sysConfigService.getValue(ConfigConstant.AIFACE_SECRET_KEY);
        String eCode = sysConfigService.getValue(ConfigConstant.AIFACE_ECODE);
        try {
            //参数验证
            paramVerify(photo != null, "参数值不能为空[photo]");

            //获取token
            Object token = getFaceToken();

            //处理请求header
            JSONObject reqHeader = new JSONObject();
            reqHeader.put("access_token", token.toString());

            //加密基本业务参数
            JSONObject json = new JSONObject();
            json.put("outid", outId);
            json.put("ecode", eCode);
            String requestData = ThreeDESUtils.encryptMode(aifaceSecretKey, json.toString());

            //处理图片和参数
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.addBinaryBody("photo", photo, ContentType.MULTIPART_FORM_DATA, UUID.randomUUID() + ".jpg");
            //获取照片签名
            HMAC_SHA1 sha1 = new HMAC_SHA1(aifaceSecretKey);
            String photoSign = sha1.genHMAC(HMAC_SHA1.getImageStr(photo.getAbsolutePath()));
            photoSign = URLEncoder.encode(photoSign, "UTF-8");
            builder.addTextBody("photosign", photoSign);
            builder.addTextBody("request_data", requestData, ContentType.APPLICATION_JSON);

            String responseText = HttpRequestUtils.httpPostMultipart(aifaceUrl + checkPhotoUrl, builder, reqHeader);
            AifaceResponse aifaceResponse = new AifaceResponse(aifaceSecretKey, responseText);
            return aifaceResponse;
        } catch (Exception e) {
            log.error("--checkpersonbyphoto--error:{}" + e);
            throw new RuntimeException("--checkpersonbyphoto--error:{}" + e.getMessage());
        }
    }

    private static Long getRemainSecondsOneDay(Date currentDate) {
        Calendar midnight = Calendar.getInstance();
        midnight.setTime(currentDate);
        midnight.add(Calendar.DAY_OF_MONTH, 1);
        midnight.set(Calendar.HOUR_OF_DAY, 0);
        midnight.set(Calendar.MINUTE, 0);
        midnight.set(Calendar.SECOND, 0);
        midnight.set(Calendar.MILLISECOND, 0);
        Long seconds = ((midnight.getTime().getTime() - currentDate.getTime()) / 1000);
        return seconds;
    }

    private static void paramVerify(boolean exp, String message) {
        if (!exp) {
            throw new RuntimeException(message);
        }
    }
}
